home *** CD-ROM | disk | FTP | other *** search
/ Acorn RISC PD-CD 1 / Acorn RISC PD-CD 1.iso / languages / gawk / c / builtin < prev    next >
Encoding:
Text File  |  1990-02-20  |  19.9 KB  |  1,037 lines

  1. /*
  2.  * builtin.c - Builtin functions and various utility procedures 
  3.  */
  4.  
  5. /* 
  6.  * Copyright (C) 1986, 1988, 1989 the Free Software Foundation, Inc.
  7.  * 
  8.  * This file is part of GAWK, the GNU implementation of the
  9.  * AWK Progamming Language.
  10.  * 
  11.  * GAWK is free software; you can redistribute it and/or modify
  12.  * it under the terms of the GNU General Public License as published by
  13.  * the Free Software Foundation; either version 1, or (at your option)
  14.  * any later version.
  15.  * 
  16.  * GAWK is distributed in the hope that it will be useful,
  17.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  19.  * GNU General Public License for more details.
  20.  * 
  21.  * You should have received a copy of the GNU General Public License
  22.  * along with GAWK; see the file COPYING.  If not, write to
  23.  * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  24.  */
  25.  
  26. #include "awk.h"
  27.  
  28. extern void srandom(unsigned);
  29. extern char *initstate(unsigned, char *, int);
  30. extern char *setstate(char *);
  31. extern long random(void);
  32.  
  33. extern NODE **fields_arr;
  34.  
  35. static void get_one(NODE *, NODE **);
  36. static void get_two(NODE *, NODE **, NODE **);
  37. static int get_three(NODE *, NODE **, NODE **, NODE **);
  38.  
  39. /* Builtin functions */
  40. NODE *
  41. do_exp(tree)
  42. NODE *tree;
  43. {
  44.     NODE *tmp;
  45.     double d, res;
  46.  
  47.     get_one(tree, &tmp);
  48.     d = force_number(tmp);
  49.     free_temp(tmp);
  50.     errno = 0;
  51.     res = exp(d);
  52.     if (errno == ERANGE)
  53.         warning("exp argument %g is out of range", d);
  54.     return tmp_number((AWKNUM) res);
  55. }
  56.  
  57. NODE *
  58. do_index(tree)
  59. NODE *tree;
  60. {
  61.     NODE *s1, *s2;
  62.     register char *p1, *p2;
  63.     register int l1, l2;
  64.     long ret;
  65.  
  66.  
  67.     get_two(tree, &s1, &s2);
  68.     force_string(s1);
  69.     force_string(s2);
  70.     p1 = s1->stptr;
  71.     p2 = s2->stptr;
  72.     l1 = s1->stlen;
  73.     l2 = s2->stlen;
  74.     ret = 0;
  75.     if (! strict && IGNORECASE_node->var_value->numbr != 0.0) {
  76.         while (l1) {
  77.             if (casetable[*p1] == casetable[*p2]
  78.                 && strnlcmp(p1, p2, l2) == 0) {
  79.                 ret = 1 + s1->stlen - l1;
  80.                 break;
  81.             }
  82.             l1--;
  83.             p1++;
  84.         }
  85.     } else {
  86.         while (l1) {
  87.             if (STREQN(p1, p2, l2)) {
  88.                 ret = 1 + s1->stlen - l1;
  89.                 break;
  90.             }
  91.             l1--;
  92.             p1++;
  93.         }
  94.     }
  95.     free_temp(s1);
  96.     free_temp(s2);
  97.     return tmp_number((AWKNUM) ret);
  98. }
  99.  
  100. NODE *
  101. do_int(tree)
  102. NODE *tree;
  103. {
  104.     NODE *tmp;
  105.     double d;
  106.  
  107.     get_one(tree, &tmp);
  108.     d = floor((double)force_number(tmp));
  109.     free_temp(tmp);
  110.     return tmp_number((AWKNUM) d);
  111. }
  112.  
  113. NODE *
  114. do_length(tree)
  115. NODE *tree;
  116. {
  117.     NODE *tmp;
  118.     int len;
  119.  
  120.     get_one(tree, &tmp);
  121.     len = force_string(tmp)->stlen;
  122.     free_temp(tmp);
  123.     return tmp_number((AWKNUM) len);
  124. }
  125.  
  126. NODE *
  127. do_log(tree)
  128. NODE *tree;
  129. {
  130.     NODE *tmp;
  131.     double d, arg;
  132.  
  133.     get_one(tree, &tmp);
  134.     arg = (double) force_number(tmp);
  135.     if (arg < 0.0)
  136.         warning("log called with negative argument %g", arg);
  137.     d = log(arg);
  138.     free_temp(tmp);
  139.     return tmp_number((AWKNUM) d);
  140. }
  141.  
  142. /*
  143.  * Note that the output buffer cannot be static because sprintf may get
  144.  * called recursively by force_string.  Hence the wasteful alloca calls 
  145.  */
  146.  
  147. /* %e and %f formats are not properly implemented.  Someone should fix them */
  148. NODE *
  149. do_sprintf(tree)
  150. NODE *tree;
  151. {
  152. #define bchunk(s,l) if(l) {\
  153.     while((l)>ofre) {\
  154.       char *tmp;\
  155.       tmp=(char *)alloca(osiz*2);\
  156.       memcpy(tmp,obuf,olen);\
  157.       obuf=tmp;\
  158.       ofre+=osiz;\
  159.       osiz*=2;\
  160.     }\
  161.     memcpy(obuf+olen,s,(l));\
  162.     olen+=(l);\
  163.     ofre-=(l);\
  164.   }
  165.  
  166.     /* Is there space for something L big in the buffer? */
  167. #define chksize(l)  if((l)>ofre) {\
  168.     char *tmp;\
  169.     tmp=(char *)alloca(osiz*2);\
  170.     memcpy(tmp,obuf,olen);\
  171.     obuf=tmp;\
  172.     ofre+=osiz;\
  173.     osiz*=2;\
  174.   }
  175.  
  176.     /*
  177.      * Get the next arg to be formatted.  If we've run out of args,
  178.      * return "" (Null string) 
  179.      */
  180. #define parse_next_arg() {\
  181.   if(!carg) arg= Nnull_string;\
  182.   else {\
  183.       get_one(carg,&arg);\
  184.     carg=carg->rnode;\
  185.   }\
  186.  }
  187.  
  188.     char *obuf;
  189.     int osiz, ofre, olen;
  190.     static char chbuf[] = "0123456789abcdef";
  191.     static char sp[] = " ";
  192.     char *s0, *s1;
  193.     int n0;
  194.     NODE *sfmt, *arg;
  195.     register NODE *carg;
  196.     long fw, prec, lj, alt, big;
  197.     long *cur;
  198.     long val;
  199. #ifdef sun386            /* Can't cast unsigned (int/long) from ptr->value */
  200.     long tmp_uval;        /* on 386i 4.0.1 C compiler -- it just hangs */
  201. #endif
  202.     unsigned long uval;
  203.     int sgn;
  204.     int base;
  205.     char cpbuf[30];        /* if we have numbers bigger than 30 */
  206.     char *cend = &cpbuf[30];/* chars, we lose, but seems unlikely */
  207.     char *cp;
  208.     char *fill;
  209.     double tmpval;
  210.     char *pr_str;
  211.     int ucasehex = 0;
  212.  
  213.     obuf = (char *) alloca(120);
  214.     osiz = 120;
  215.     ofre = osiz;
  216.     olen = 0;
  217.     get_one(tree, &sfmt);
  218.     sfmt = force_string(sfmt);
  219.     carg = tree->rnode;
  220.     for (s0 = s1 = sfmt->stptr, n0 = sfmt->stlen; n0-- > 0;) {
  221.         if (*s1 != '%') {
  222.             s1++;
  223.             continue;
  224.         }
  225.         bchunk(s0, s1 - s0);
  226.         s0 = s1;
  227.         cur = &fw;
  228.         fw = 0;
  229.         prec = 0;
  230.         lj = alt = big = 0;
  231.         fill = sp;
  232.         cp = cend;
  233.         s1++;
  234.  
  235. retry:
  236.         --n0;
  237.         switch (*s1++) {
  238.         case '%':
  239.             bchunk("%", 1);
  240.             s0 = s1;
  241.             break;
  242.  
  243.         case '0':
  244.             if (fill != sp || lj)
  245.                 goto lose;
  246.             if (cur == &fw)
  247.                 fill = "0";    /* FALL through */
  248.         case '1':
  249.         case '2':
  250.         case '3':
  251.         case '4':
  252.         case '5':
  253.         case '6':
  254.         case '7':
  255.         case '8':
  256.         case '9':
  257.             if (cur == 0)
  258.                 goto lose;
  259.             *cur = s1[-1] - '0';
  260.             while (n0 > 0 && *s1 >= '0' && *s1 <= '9') {
  261.                 --n0;
  262.                 *cur = *cur * 10 + *s1++ - '0';
  263.             }
  264.             goto retry;
  265. #ifdef not_yet
  266.         case ' ':        /* print ' ' or '-' */
  267.         case '+':        /* print '+' or '-' */
  268. #endif
  269.         case '-':
  270.             if (lj || fill != sp)
  271.                 goto lose;
  272.             lj++;
  273.             goto retry;
  274.         case '.':
  275.             if (cur != &fw)
  276.                 goto lose;
  277.             cur = ≺
  278.             goto retry;
  279.         case '#':
  280.             if (alt)
  281.                 goto lose;
  282.             alt++;
  283.             goto retry;
  284.         case 'l':
  285.             if (big)
  286.                 goto lose;
  287.             big++;
  288.             goto retry;
  289.         case 'c':
  290.             parse_next_arg();
  291.             if (arg->flags & NUMERIC) {
  292. #ifdef sun386
  293.                 tmp_uval = arg->numbr; 
  294.                 uval= (unsigned long) tmp_uval;
  295. #else
  296.                 uval = (unsigned long) arg->numbr;
  297. #endif
  298.                 cpbuf[0] = uval;
  299.                 prec = 1;
  300.                 pr_str = cpbuf;
  301.                 goto dopr_string;
  302.             }
  303.             if (! prec)
  304.                 prec = 1;
  305.             else if (prec > arg->stlen)
  306.                 prec = arg->stlen;
  307.             pr_str = arg->stptr;
  308.             goto dopr_string;
  309.         case 's':
  310.             parse_next_arg();
  311.             arg = force_string(arg);
  312.             if (!prec || prec > arg->stlen)
  313.                 prec = arg->stlen;
  314.             pr_str = arg->stptr;
  315.  
  316.     dopr_string:
  317.             if (fw > prec && !lj) {
  318.                 while (fw > prec) {
  319.                     bchunk(sp, 1);
  320.                     fw--;
  321.                 }
  322.             }
  323.             bchunk(pr_str, (int) prec);
  324.             if (fw > prec) {
  325.                 while (fw > prec) {
  326.                     bchunk(sp, 1);
  327.                     fw--;
  328.                 }
  329.             }
  330.             s0 = s1;
  331.             free_temp(arg);
  332.             break;
  333.         case 'd':
  334.         case 'i':
  335.             parse_next_arg();
  336.             val = (long) force_number(arg);
  337.             free_temp(arg);
  338.             if (val < 0) {
  339.                 sgn = 1;
  340.                 val = -val;
  341.             } else
  342.                 sgn = 0;
  343.             do {
  344.                 *--cp = '0' + val % 10;
  345.                 val /= 10;
  346.             } while (val);
  347.             if (sgn)
  348.                 *--cp = '-';
  349.             if (prec > fw)
  350.                 fw = prec;
  351.             prec = cend - cp;
  352.             if (fw > prec && !lj) {
  353.                 if (fill != sp && *cp == '-') {
  354.                     bchunk(cp, 1);
  355.                     cp++;
  356.                     prec--;
  357.                     fw--;
  358.                 }
  359.                 while (fw > prec) {
  360.                     bchunk(fill, 1);
  361.                     fw--;
  362.                 }
  363.             }
  364.             bchunk(cp, (int) prec);
  365.             if (fw > prec) {
  366.                 while (fw > prec) {
  367.                     bchunk(fill, 1);
  368.                     fw--;
  369.                 }
  370.             }
  371.             s0 = s1;
  372.             break;
  373.         case 'u':
  374.             base = 10;
  375.             goto pr_unsigned;
  376.         case 'o':
  377.             base = 8;
  378.             goto pr_unsigned;
  379.         case 'X':
  380.             ucasehex = 1;
  381.         case 'x':
  382.             base = 16;
  383.             goto pr_unsigned;
  384.     pr_unsigned:
  385.             parse_next_arg();
  386.             uval = (unsigned long) force_number(arg);
  387.             free_temp(arg);
  388.             do {
  389.                 *--cp = chbuf[uval % base];
  390.                 if (ucasehex && isalpha(*cp))
  391.                     *cp = toupper(*cp);
  392.                 uval /= base;
  393.             } while (uval);
  394.             if (alt && (base == 8 || base == 16)) {
  395.                 if (base == 16) {
  396.                     if (ucasehex)
  397.                         *--cp = 'X';
  398.                     else
  399.                         *--cp = 'x';
  400.                 }
  401.                 *--cp = '0';
  402.             }
  403.             prec = cend - cp;
  404.             if (fw > prec && !lj) {
  405.                 while (fw > prec) {
  406.                     bchunk(fill, 1);
  407.                     fw--;
  408.                 }
  409.             }
  410.             bchunk(cp, (int) prec);
  411.             if (fw > prec) {
  412.                 while (fw > prec) {
  413.                     bchunk(fill, 1);
  414.                     fw--;
  415.                 }
  416.             }
  417.             s0 = s1;
  418.             break;
  419.         case 'g':
  420.             parse_next_arg();
  421.             tmpval = force_number(arg);
  422.             free_temp(arg);
  423.             if (prec == 0)
  424.                 prec = 13;
  425.             (void) sprintf(cpbuf, "%*g", (int) prec, tmpval);
  426.             prec = strlen(cpbuf);
  427.             cp = cpbuf;
  428.             if (fw > prec && !lj) {
  429.                 if (fill != sp && *cp == '-') {
  430.                     bchunk(cp, 1);
  431.                     cp++;
  432.                     prec--;
  433.                 }    /* Deal with .5 as 0.5 */
  434.                 if (fill == sp && *cp == '.') {
  435.                     --fw;
  436.                     while (--fw >= prec) {
  437.                         bchunk(fill, 1);
  438.                     }
  439.                     bchunk("0", 1);
  440.                 } else
  441.                     while (fw-- > prec)
  442.                         bchunk(fill, 1);
  443.             } else {/* Turn .5 into 0.5 */
  444.                 /* FOO */
  445.                 if (*cp == '.' && fill == sp) {
  446.                     bchunk("0", 1);
  447.                     --fw;
  448.                 }
  449.             }
  450.             bchunk(cp, (int) prec);
  451.             if (fw > prec)
  452.                 while (fw-- > prec)
  453.                     bchunk(fill, 1);
  454.             s0 = s1;
  455.             break;
  456.         case 'f':
  457.             parse_next_arg();
  458.             tmpval = force_number(arg);
  459.             free_temp(arg);
  460.             chksize(fw + prec + 5);    /* 5==slop */
  461.  
  462.             cp = cpbuf;
  463.             *cp++ = '%';
  464.             if (lj)
  465.                 *cp++ = '-';
  466.             if (fill != sp)
  467.                 *cp++ = '0';
  468.             if (cur != &fw) {
  469.                 (void) strcpy(cp, "*.*f");
  470.                 (void) sprintf(obuf + olen, cpbuf, (int) fw, (int) prec, (double) tmpval);
  471.             } else {
  472.                 (void) strcpy(cp, "*f");
  473.                 (void) sprintf(obuf + olen, cpbuf, (int) fw, (double) tmpval);
  474.             }
  475.             ofre -= strlen(obuf + olen);
  476.             olen += strlen(obuf + olen);    /* There may be nulls */
  477.             s0 = s1;
  478.             break;
  479.         case 'e':
  480.             parse_next_arg();
  481.             tmpval = force_number(arg);
  482.             free_temp(arg);
  483.             chksize(fw + prec + 5);    /* 5==slop */
  484.             cp = cpbuf;
  485.             *cp++ = '%';
  486.             if (lj)
  487.                 *cp++ = '-';
  488.             if (fill != sp)
  489.                 *cp++ = '0';
  490.             if (cur != &fw) {
  491.                 (void) strcpy(cp, "*.*e");
  492.                 (void) sprintf(obuf + olen, cpbuf, (int) fw, (int) prec, (double) tmpval);
  493.             } else {
  494.                 (void) strcpy(cp, "*e");
  495.                 (void) sprintf(obuf + olen, cpbuf, (int) fw, (double) tmpval);
  496.             }
  497.             ofre -= strlen(obuf + olen);
  498.             olen += strlen(obuf + olen);    /* There may be nulls */
  499.             s0 = s1;
  500.             break;
  501.  
  502.         default:
  503.     lose:
  504.             break;
  505.         }
  506.     }
  507.     bchunk(s0, s1 - s0);
  508.     free_temp(sfmt);
  509.     return tmp_string(obuf, olen);
  510. }
  511.  
  512. void
  513. do_printf(tree)
  514. NODE *tree;
  515. {
  516.     struct redirect *rp = NULL;
  517.     register FILE *fp = stdout;
  518.     int errflg = 0;        /* not used, sigh */
  519.  
  520.     if (tree->rnode) {
  521.         rp = redirect(tree->rnode, &errflg);
  522.         if (rp)
  523.             fp = rp->fp;
  524.     }
  525.     if (fp)
  526.         print_simple(do_sprintf(tree->lnode), fp);
  527. }
  528.  
  529. NODE *
  530. do_sqrt(tree)
  531. NODE *tree;
  532. {
  533.     NODE *tmp;
  534.     double d, arg;
  535.  
  536.     get_one(tree, &tmp);
  537.     arg = (double) force_number(tmp);
  538.     if (arg < 0.0)
  539.         warning("sqrt called with negative argument %g", arg);
  540.     d = sqrt(arg);
  541.     free_temp(tmp);
  542.     return tmp_number((AWKNUM) d);
  543. }
  544.  
  545. NODE *
  546. do_substr(tree)
  547. NODE *tree;
  548. {
  549.     NODE *t1, *t2, *t3;
  550.     NODE *r;
  551.     register int indx, length;
  552.  
  553.     t1 = t2 = t3 = NULL;
  554.     length = -1;
  555.     if (get_three(tree, &t1, &t2, &t3) == 3)
  556.         length = (int) force_number(t3);
  557.     indx = (int) force_number(t2) - 1;
  558.     t1 = force_string(t1);
  559.     if (length == -1)
  560.         length = t1->stlen;
  561.     if (indx < 0)
  562.         indx = 0;
  563.     if (indx >= t1->stlen || length <= 0) {
  564.         if (t3)
  565.             free_temp(t3);
  566.         free_temp(t2);
  567.         free_temp(t1);
  568.         return Nnull_string;
  569.     }
  570.     if (indx + length > t1->stlen)
  571.         length = t1->stlen - indx;
  572.     if (t3)
  573.         free_temp(t3);
  574.     free_temp(t2);
  575.     r =  tmp_string(t1->stptr + indx, length);
  576.     free_temp(t1);
  577.     return r;
  578. }
  579.  
  580. NODE *
  581. do_system(tree)
  582. NODE *tree;
  583. {
  584.     NODE *tmp;
  585.     int ret;
  586.  
  587.     (void) flush_io ();    /* so output is synchronous with gawk's */
  588.     get_one(tree, &tmp);
  589.     (void)system("Set Sys$ReturnCode 0");    /* Clear old return code */
  590.     ret = system(force_string(tmp)->stptr);
  591.     free_temp(tmp);
  592.     return tmp_number((AWKNUM) ret);
  593. }
  594.  
  595. void 
  596. do_print(tree)
  597. register NODE *tree;
  598. {
  599.     struct redirect *rp = NULL;
  600.     register FILE *fp = stdout;
  601.     int errflg = 0;        /* not used, sigh */
  602.  
  603.     if (tree->rnode) {
  604.         rp = redirect(tree->rnode, &errflg);
  605.         if (rp)
  606.             fp = rp->fp;
  607.     }
  608.     if (!fp)
  609.         return;
  610.     tree = tree->lnode;
  611.     if (!tree)
  612.         tree = WHOLELINE;
  613.     if (tree->type != Node_expression_list) {
  614.         if (!(tree->flags & STR))
  615.             cant_happen();
  616.         print_simple(tree, fp);
  617.     } else {
  618.         while (tree) {
  619.             print_simple(force_string(tree_eval(tree->lnode)), fp);
  620.             tree = tree->rnode;
  621.             if (tree)
  622.                 print_simple(OFS_node->var_value, fp);
  623.         }
  624.     }
  625.     print_simple(ORS_node->var_value, fp);
  626. }
  627.  
  628. NODE *
  629. do_tolower(tree)
  630. NODE *tree;
  631. {
  632.     NODE *t1, *t2;
  633.     register char *cp, *cp2;
  634.  
  635.     get_one(tree, &t1);
  636.     t1 = force_string(t1);
  637.     t2 = tmp_string(t1->stptr, t1->stlen);
  638.     for (cp = t2->stptr, cp2 = t2->stptr + t2->stlen; cp < cp2; cp++)
  639.         if (isupper(*cp))
  640.             *cp = tolower(*cp);
  641.     free_temp(t1);
  642.     return t2;
  643. }
  644.  
  645. NODE *
  646. do_toupper(tree)
  647. NODE *tree;
  648. {
  649.     NODE *t1, *t2;
  650.     register char *cp;
  651.  
  652.     get_one(tree, &t1);
  653.     t1 = force_string(t1);
  654.     t2 = tmp_string(t1->stptr, t1->stlen);
  655.     for (cp = t2->stptr; cp < t2->stptr + t2->stlen; cp++)
  656.         if (islower(*cp))
  657.             *cp = toupper(*cp);
  658.     free_temp(t1);
  659.     return t2;
  660. }
  661.  
  662. /*
  663.  * Get the arguments to functions.  No function cares if you give it too many
  664.  * args (they're ignored).  Only a few fuctions complain about being given
  665.  * too few args.  The rest have defaults.
  666.  */
  667.  
  668. static void
  669. get_one(tree, res)
  670. NODE *tree, **res;
  671. {
  672.     if (!tree) {
  673.         *res = WHOLELINE;
  674.         return;
  675.     }
  676.     *res = tree_eval(tree->lnode);
  677. }
  678.  
  679. static void
  680. get_two(tree, res1, res2)
  681. NODE *tree, **res1, **res2;
  682. {
  683.     if (!tree) {
  684.         *res1 = WHOLELINE;
  685.         return;
  686.     }
  687.     *res1 = tree_eval(tree->lnode);
  688.     if (!tree->rnode)
  689.         return;
  690.     tree = tree->rnode;
  691.     *res2 = tree_eval(tree->lnode);
  692. }
  693.  
  694. static int
  695. get_three(tree, res1, res2, res3)
  696. NODE *tree, **res1, **res2, **res3;
  697. {
  698.     if (!tree) {
  699.         *res1 = WHOLELINE;
  700.         return 0;
  701.     }
  702.     *res1 = tree_eval(tree->lnode);
  703.     if (!tree->rnode)
  704.         return 1;
  705.     tree = tree->rnode;
  706.     *res2 = tree_eval(tree->lnode);
  707.     if (!tree->rnode)
  708.         return 2;
  709.     tree = tree->rnode;
  710.     *res3 = tree_eval(tree->lnode);
  711.     return 3;
  712. }
  713.  
  714. int
  715. a_get_three(tree, res1, res2, res3)
  716. NODE *tree, **res1, **res2, **res3;
  717. {
  718.     if (!tree) {
  719.         *res1 = WHOLELINE;
  720.         return 0;
  721.     }
  722.     *res1 = tree_eval(tree->lnode);
  723.     if (!tree->rnode)
  724.         return 1;
  725.     tree = tree->rnode;
  726.     *res2 = tree->lnode;
  727.     if (!tree->rnode)
  728.         return 2;
  729.     tree = tree->rnode;
  730.     *res3 = tree_eval(tree->lnode);
  731.     return 3;
  732. }
  733.  
  734. void
  735. print_simple(tree, fp)
  736. NODE *tree;
  737. FILE *fp;
  738. {
  739.     if (fwrite(tree->stptr, sizeof(char), tree->stlen, fp) != tree->stlen)
  740.         warning("fwrite: unable to write");
  741.     free_temp(tree);
  742. }
  743.  
  744. NODE *
  745. do_atan2(tree)
  746. NODE *tree;
  747. {
  748.     NODE *t1, *t2;
  749.     double d1, d2;
  750.  
  751.     get_two(tree, &t1, &t2);
  752.     d1 = force_number(t1);
  753.     d2 = force_number(t2);
  754.     free_temp(t1);
  755.     free_temp(t2);
  756.     return tmp_number((AWKNUM) atan2(d1, d2));
  757. }
  758.  
  759. NODE *
  760. do_sin(tree)
  761. NODE *tree;
  762. {
  763.     NODE *tmp;
  764.     double d;
  765.  
  766.     get_one(tree, &tmp);
  767.     d = sin((double)force_number(tmp));
  768.     free_temp(tmp);
  769.     return tmp_number((AWKNUM) d);
  770. }
  771.  
  772. NODE *
  773. do_cos(tree)
  774. NODE *tree;
  775. {
  776.     NODE *tmp;
  777.     double d;
  778.  
  779.     get_one(tree, &tmp);
  780.     d = cos((double)force_number(tmp));
  781.     free_temp(tmp);
  782.     return tmp_number((AWKNUM) d);
  783. }
  784.  
  785. static int firstrand = 1;
  786. static char state[256];
  787.  
  788. #define    MAXLONG    2147483647    /* maximum value for long int */
  789.  
  790. /* ARGSUSED */
  791. NODE *
  792. do_rand(tree)
  793. NODE *tree;
  794. {
  795.     if (firstrand) {
  796.         (void) initstate((unsigned) 1, state, sizeof state);
  797.         srandom(1);
  798.         firstrand = 0;
  799.     }
  800.     return tmp_number((AWKNUM) random() / MAXLONG);
  801. }
  802.  
  803. NODE *
  804. do_srand(tree)
  805. NODE *tree;
  806. {
  807.     NODE *tmp;
  808.     static long save_seed = 1;
  809.     long ret = save_seed;    /* SVR4 awk srand returns previous seed */
  810.  
  811.     if (firstrand)
  812.         (void) initstate((unsigned) 1, state, sizeof state);
  813.     else
  814.         (void) setstate(state);
  815.  
  816.     if (!tree)
  817.         srandom((int) (save_seed = time(NULL)));
  818.     else {
  819.         get_one(tree, &tmp);
  820.         srandom((int) (save_seed = (long) force_number(tmp)));
  821.         free_temp(tmp);
  822.     }
  823.     firstrand = 0;
  824.     return tmp_number((AWKNUM) ret);
  825. }
  826.  
  827. NODE *
  828. do_match(tree)
  829. NODE *tree;
  830. {
  831.     NODE *t1;
  832.     int rstart;
  833.     struct re_registers reregs;
  834.     struct re_pattern_buffer *rp;
  835.     int need_to_free = 0;
  836.  
  837.     t1 = force_string(tree_eval(tree->lnode));
  838.     tree = tree->rnode;
  839.     if (tree == NULL || tree->lnode == NULL)
  840.         fatal("match called with only one argument");
  841.     tree = tree->lnode;
  842.     if (tree->type == Node_regex) {
  843.         rp = tree->rereg;
  844.         if (!strict && ((IGNORECASE_node->var_value->numbr != 0)
  845.             ^ (tree->re_case != 0))) {
  846.             /* recompile since case sensitivity differs */
  847.             rp = tree->rereg =
  848.                 mk_re_parse(tree->re_text,
  849.                 (IGNORECASE_node->var_value->numbr != 0));
  850.             tree->re_case =
  851.                 (IGNORECASE_node->var_value->numbr != 0);
  852.         }
  853.     } else {
  854.         need_to_free = 1;
  855.         rp = make_regexp(force_string(tree_eval(tree)),
  856.                 (IGNORECASE_node->var_value->numbr != 0));
  857.         if (rp == NULL)
  858.             cant_happen();
  859.     }
  860.     rstart = re_search(rp, t1->stptr, t1->stlen, 0, t1->stlen, &reregs);
  861.     free_temp(t1);
  862.     if (rstart >= 0) {
  863.         rstart++;    /* 1-based indexing */
  864.         /* RSTART set to rstart below */
  865.         RLENGTH_node->var_value->numbr =
  866.             (AWKNUM) (reregs.end[0] - reregs.start[0]);
  867.     } else {
  868.         /*
  869.          * Match failed. Set RSTART to 0, RLENGTH to -1.
  870.          * Return the value of RSTART.
  871.          */
  872.         rstart = 0;    /* used as return value */
  873.         RLENGTH_node->var_value->numbr = -1.0;
  874.     }
  875.     RSTART_node->var_value->numbr = (AWKNUM) rstart;
  876.     if (need_to_free) {
  877.         free(rp->buffer);
  878.         free(rp->fastmap);
  879.         free((char *) rp);
  880.     }
  881.     return tmp_number((AWKNUM) rstart);
  882. }
  883.  
  884. static NODE *
  885. sub_common(tree, global)
  886. NODE *tree;
  887. int global;
  888. {
  889.     register int len;
  890.     register char *scan;
  891.     register char *bp, *cp;
  892.     int search_start = 0;
  893.     int match_length;
  894.     int matches = 0;
  895.     char *buf;
  896.     struct re_pattern_buffer *rp;
  897.     NODE *s;        /* subst. pattern */
  898.     NODE *t;        /* string to make sub. in; $0 if none given */
  899.     struct re_registers reregs;
  900.     unsigned int saveflags;
  901.     NODE *tmp;
  902.     NODE **lhs;
  903.     char *lastbuf;
  904.     int need_to_free = 0;
  905.  
  906.     if (tree == NULL)
  907.         fatal("sub or gsub called with 0 arguments");
  908.     tmp = tree->lnode;
  909.     if (tmp->type == Node_regex) {
  910.         rp = tmp->rereg;
  911.         if (! strict && ((IGNORECASE_node->var_value->numbr != 0)
  912.             ^ (tmp->re_case != 0))) {
  913.             /* recompile since case sensitivity differs */
  914.             rp = tmp->rereg =
  915.                 mk_re_parse(tmp->re_text,
  916.                 (IGNORECASE_node->var_value->numbr != 0));
  917.             tmp->re_case = (IGNORECASE_node->var_value->numbr != 0);
  918.         }
  919.     } else {
  920.         need_to_free = 1;
  921.         rp = make_regexp(force_string(tree_eval(tmp)),
  922.                 (IGNORECASE_node->var_value->numbr != 0));
  923.         if (rp == NULL)
  924.             cant_happen();
  925.     }
  926.     tree = tree->rnode;
  927.     if (tree == NULL)
  928.         fatal("sub or gsub called with only 1 argument");
  929.     s = force_string(tree_eval(tree->lnode));
  930.     tree = tree->rnode;
  931.     deref = 0;
  932.     field_num = -1;
  933.     if (tree == NULL) {
  934.         t = node0_valid ? fields_arr[0] : *get_field(0, 0);
  935.         lhs = &fields_arr[0];
  936.         field_num = 0;
  937.         deref = t;
  938.     } else {
  939.         t = tree->lnode;
  940.         lhs = get_lhs(t, 1);
  941.         t = force_string(tree_eval(t));
  942.     }
  943.     /*
  944.      * create a private copy of the string
  945.      */
  946.     if (t->stref > 1 || (t->flags & PERM)) {
  947.         saveflags = t->flags;
  948.         t->flags &= ~MALLOC;
  949.         tmp = dupnode(t);
  950.         t->flags = saveflags;
  951.         do_deref();
  952.         t = tmp;
  953.         if (lhs)
  954.             *lhs = tmp;
  955.     }
  956.     lastbuf = t->stptr;
  957.     do {
  958.         if (re_search(rp, t->stptr, t->stlen, search_start,
  959.             t->stlen-search_start, &reregs) == -1
  960.             || reregs.start[0] == reregs.end[0])
  961.             break;
  962.         matches++;
  963.  
  964.         /*
  965.          * first, make a pass through the sub. pattern, to calculate
  966.          * the length of the string after substitution 
  967.          */
  968.         match_length = reregs.end[0] - reregs.start[0];
  969.         len = t->stlen - match_length;
  970.         for (scan = s->stptr; scan < s->stptr + s->stlen; scan++)
  971.             if (*scan == '&')
  972.                 len += match_length;
  973.             else if (*scan == '\\' && *(scan+1) == '&') {
  974.                 scan++;
  975.                 len++;
  976.             } else
  977.                 len++;
  978.         emalloc(buf, char *, len + 1, "do_sub");
  979.         bp = buf;
  980.  
  981.         /*
  982.          * now, create the result, copying in parts of the original
  983.          * string 
  984.          */
  985.         for (scan = t->stptr; scan < t->stptr + reregs.start[0]; scan++)
  986.             *bp++ = *scan;
  987.         for (scan = s->stptr; scan < s->stptr + s->stlen; scan++)
  988.             if (*scan == '&')
  989.                 for (cp = t->stptr + reregs.start[0];
  990.                      cp < t->stptr + reregs.end[0]; cp++)
  991.                     *bp++ = *cp;
  992.             else if (*scan == '\\' && *(scan+1) == '&') {
  993.                 scan++;
  994.                 *bp++ = *scan;
  995.             } else
  996.                 *bp++ = *scan;
  997.         search_start = bp - buf;
  998.         for (scan = t->stptr + reregs.end[0];
  999.              scan < t->stptr + t->stlen; scan++)
  1000.             *bp++ = *scan;
  1001.         *bp = '\0';
  1002.         free(lastbuf);
  1003.         t->stptr = buf;
  1004.         lastbuf = buf;
  1005.         t->stlen = len;
  1006.     } while (global && search_start < t->stlen);
  1007.  
  1008.     free_temp(s);
  1009.     if (need_to_free) {
  1010.         free(rp->buffer);
  1011.         free(rp->fastmap);
  1012.         free((char *) rp);
  1013.     }
  1014.     if (matches > 0) {
  1015.         if (field_num == 0)
  1016.             set_record(fields_arr[0]->stptr, fields_arr[0]->stlen);
  1017.         t->flags &= ~(NUM|NUMERIC);
  1018.     }
  1019.     field_num = -1;
  1020.     return tmp_number((AWKNUM) matches);
  1021. }
  1022.  
  1023. NODE *
  1024. do_gsub(tree)
  1025. NODE *tree;
  1026. {
  1027.     return sub_common(tree, 1);
  1028. }
  1029.  
  1030. NODE *
  1031. do_sub(tree)
  1032. NODE *tree;
  1033. {
  1034.     return sub_common(tree, 0);
  1035. }
  1036.  
  1037.